#include "airmouse_jni.h"

int airMouseMix(float minStep, float* inputArray, float* outputArray)
{
    // CN:Z轴向上时，鼠标位移量
    float x1, y1;
    // CN:X轴向上时，鼠标位移量
    float x2, y2;
    // CN:不同方向位移量权值
    float v1, v2;

    // limitGyro();
    /*
    // CN:地磁偏转角度
    float Rot0 = newRotation[0] - preRotation[0];
    if (Rot0 < -180)
    {
        Rot0 = 360 + Rot0;
    }
    // CN:Y轴与水平偏角
    float Rot1 = newRotation[1] - preRotation[1];
    */

    // CN:使用加速度对转角进行加成
    float weight_accX = 1;
    float weight_accZ = 1;
    // weight_accX = (float) Math.abs(mAirData.newAccX - mAirData.preAccX);
    // weight_accZ = (float) Math.abs(mAirData.newAccZ - mAirData.preAccZ);

    // CN:Z轴向上
    x1 = ((-WEIGHT_GYR_X) * weight_accX * inputArray[2]);
    // + (WEIGHT_ROT_X * Rot0);
    y1 = ((-WEIGHT_GYR_Y) * weight_accZ * inputArray[0]);
    // + (WEIGHT_ROT_Y * Rot1);
    // + (-WEIGHT_ACC_Y) * (accZ- preAccZ);

    // CN:X轴向上
    x2 = ((-WEIGHT_GYR_X) * weight_accZ * inputArray[0]);
    //    + (WEIGHT_ROT_X * Rot0);
    // + (-WEIGHT_ACC_X) * (accZ - preAccZ);
    y2 = ((WEIGHT_GYR_Y) * weight_accX * inputArray[2]);
    //    + (WEIGHT_ROT_Y * Rot1);
    // + (-WEIGHT_ACC_Y) * (accZ - preAccZ);

    // CN:计算方向权重，用三轴重力感应
    v1 = (inputArray[5] / GRAVITY_EARTH);
    v2 = (inputArray[3] / GRAVITY_EARTH);

    outputArray[0] = v1 * x1 + v2 * x2;
    outputArray[1] = v1 * y1 + v2 * y2;

    return HI_SUCCESS;
}

float MathAbs(float param)
{
    if(param < 0)
    {
        param = 0 - param;
    }
    return param;
}

float antiShake(float mouseMove, float min_step, float max_step)
{
    if (MathAbs(mouseMove) < min_step)
    {
        mouseMove = 0;
    }
    else if (mouseMove > max_step)
    {
        mouseMove = max_step;
    }
    else if (mouseMove < -max_step)
    {
        mouseMove = -max_step;
    }

    return mouseMove;
}

int antiShake(float minStep, float* inputArray, float* outputArray)
{
    outputArray[0]=antiShake(outputArray[0], minStep, MAX_MOVE_STEP);
    outputArray[1]=antiShake(outputArray[1], minStep, MAX_MOVE_STEP);
    return HI_SUCCESS;
}


int airMouseHandle(float minStep, float* inputArray, float* outputArray)
{
    // air mouse coord
    airMouseMix(minStep, inputArray, outputArray);
    // anti-shake
    antiShake(minStep, inputArray, outputArray);

    return HI_SUCCESS;
}

jint native_getAirCoord(JNIEnv* env, jobject thiz, jfloat minStep, jfloatArray input, jfloatArray output)
{
    jfloat* fltInput;
    jfloat* fltOut;

    // get java array.
    fltInput = env->GetFloatArrayElements(input, NULL);
    fltOut = env->GetFloatArrayElements(output, NULL);

    // handle air mouse.
    airMouseHandle(minStep, fltInput, fltOut);

    // do release.
    env->ReleaseFloatArrayElements(input, (jfloat*)fltInput, 0);
    env->ReleaseFloatArrayElements(output, (jfloat*)fltOut, 0);

    return HI_SUCCESS;
}

static JNINativeMethod methods[] =
{
    {"native_getAirCoord", "(F[F[F)I", (void *)native_getAirCoord},
};

/*
 * Register several native methods for one class.
 */
static int registerNativeMethods(JNIEnv* env, const char* className,
                                 JNINativeMethod* gMethods, int numMethods)
{
    jclass clazz;

    clazz = env->FindClass(className);
    if (clazz == NULL)
    {
        LOGE("Native registration unable to find class '%s'", className);
        return JNI_FALSE;
    }
    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0)
    {
        LOGE("RegisterNatives failed for '%s'", className);
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

/*
 * Register native methods for all classes we know about.
 *
 * returns JNI_TRUE on success.
 */
static int registerNatives(JNIEnv* env)
{
    if (registerNativeMethods(env, classPathName,
                               methods, sizeof(methods) / sizeof(methods[0])) <0 )
    {
        return -1;
    }

    return 0;
}


// ----------------------------------------------------------------------------

/*
 * This is called by the VM when the shared library is first loaded.
 */

typedef union
{
    JNIEnv* env;
    void* venv;
} UnionJNIEnvToVoid;

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    UnionJNIEnvToVoid uenv;
    uenv.venv = NULL;
    jint result = -1;
    JNIEnv* env = NULL;

    if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK)
    {
        LOGE("ERROR: GetEnv failed");
        goto fail;
    }
    env = uenv.env;

    if (registerNatives(env) < 0)
    {
        LOGE("ERROR: registerNatives failed");
        goto fail;
    }

    result = JNI_VERSION_1_4;

fail:
    return result;
}
